package com.violet.common.util;

import lombok.Getter;
import org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;

/**
 * 类说明: ras加密工具类
 *
 * @author wqf
 * @date 2023/7/11 8:45
 */
@Getter
@Component
public class RsaUtil {

    /**
     * 私钥文件路径
     */
    private static final String PRIVATE_KEY_PATH = "privateKey.txt";
    /**
     * 公钥文件路径
     */
    private static final String PUBLIC_KEY_PATH = "publicKey.txt";

    public static KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        KeyPair keyPair = keyGen.generateKeyPair();
        System.out.println("生成私钥：" + getPrivateKeyString(keyPair.getPrivate()));
        System.out.println("生成公钥：" + getPublicKeyString(keyPair.getPublic()));
        return keyGen.generateKeyPair();
    }

    /**
     * 方法描述: 获取公钥字符串
     *
     * @param publicKey 公钥对象
     * @return java.lang.String
     * @author wqf
     * @date 2023/7/11 9:10
     */
    public static String getPublicKeyString(PublicKey publicKey) {
        byte[] publicKeyBytes = publicKey.getEncoded();
        return Base64.getEncoder().encodeToString(publicKeyBytes);
    }

    /**
     * 方法描述: 获取私钥字符串
     *
     * @param privateKey 私钥对象
     * @return java.lang.String
     * @author wqf
     * @date 2023/7/11 9:11
     */
    public static String getPrivateKeyString(PrivateKey privateKey) {
        byte[] privateKeyBytes = privateKey.getEncoded();
        return Base64.getEncoder().encodeToString(privateKeyBytes);
    }

    /**
     * 方法描述: 获取公钥对象
     *
     * @return java.security.PublicKey
     * @author wqf
     * @date 2023/7/11 9:12
     */
    public static PublicKey getPublicKey() throws Exception {
        byte[] publicKeyBytes = Base64.getDecoder().decode(read(PUBLIC_KEY_PATH));
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(publicKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * 方法描述: 获取公钥对象
     *
     * @return java.security.PrivateKey
     * @author wqf
     * @date 2023/7/11 9:13
     */
    public static PrivateKey getPrivateKey() throws Exception {
        byte[] privateKeyBytes = Base64.getDecoder().decode(read(PRIVATE_KEY_PATH));
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(keySpec);
    }

    /**
     * 方法描述: 数据签名
     *
     * @param privateKey 私钥对象
     * @param data       签名数据
     * @return byte[]
     * @author wqf
     * @date 2023/7/11 9:13
     */
    public static byte[] sign(PrivateKey privateKey, byte[] data) throws Exception {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(data);
        return signature.sign();
    }

    /**
     * 方法描述: 数据验签
     *
     * @param publicKey 公钥对象
     * @param data      原始数据
     * @param signature 签名后的数据
     * @return boolean
     * @author wqf
     * @date 2023/7/11 9:14
     */
    public static boolean verify(PublicKey publicKey, byte[] data, byte[] signature) throws Exception {
        Signature verifier = Signature.getInstance("SHA256withRSA");
        verifier.initVerify(publicKey);
        verifier.update(data);
        return verifier.verify(signature);
    }

    /**
     * 方法描述: 公钥加密
     *
     * @param data 加密数据
     * @return byte[]
     * @author wqf
     * @date 2023/7/11 9:00
     */
    public static String encrypt(byte[] data) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, getPublicKey());
        byte[] bytes = cipher.doFinal(data);
        return new String(bytes, StandardCharsets.UTF_8);
    }

    /**
     * 方法描述: 私钥解密
     *
     * @param encryptedData 私钥解密
     * @return byte[]
     * @author wqf
     * @date 2023/7/11 9:01
     */
    public static String decrypt(String encryptedData) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, getPrivateKey());
        byte[] decryptedData = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
        // 解密后的数据
        return new String(decryptedData, StandardCharsets.UTF_8);
    }

    /**
     * 方法描述: 读取文件内容
     * 当前方法用于读取txt文件中的公钥私钥数据
     *
     * @param filePath 文件路径
     * @return java.lang.String
     * @author wqf
     * @date 2023/7/11 10:23
     */
    public static String read(String filePath) {
        StringBuilder sb = new StringBuilder();
        try (InputStream inputStream = RsaUtil.class.getClassLoader().getResourceAsStream(filePath)) {
            assert inputStream != null;
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sb.toString();
    }
}